<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script>
  /* 
    1. 使用函数方法书写一段程序，判断一个数是不是完美数。
    如果一个数恰好等于它的因数之和，则称该数为“完美数”。
    例如：第1个完全数是6，它有因数1、2、3、6，除去它本身6外，其余3个数相加，1+2+3=6。
   */
   function perfectNum(n) {
     var sum = 0;
    //  求除了本身外的因数
     for(var i = 0; i < n; i++) {
       if (n % i == 0) {
         sum += i;
       }
     }
    // 除去本身的因数相加等于自己的，则为完美数
     if (sum == n) {
       console.log(n + "是完美数!");
     } else {
       console.log(n + "不是完美数!");
     }
   }
  //  调用函数
  perfectNum(496);
  perfectNum(125);
  
  
  /* 
  2.盈数是一种特殊的自然数，除去它本身以外的一切正约数的和大于它本身。与完美数类似。
    使用函数方法编写一段程序。
    输出1~100的所有盈数。
 */
  function abundantNum() {
    var sum = 0;
    for (var i = 1; i <= 100; i++) {
      if (i % 2 != 0) {
        // 质数一定不是盈数，遇到质数则跳过
        continue;
      }else {
        // 求除去本身的约数和
        for(var j = 1; j < i; j++) {
          if (i % j == 0){
            sum += j;
          }
        }
        // 除去本身的约数大于它自己的，则为盈数
        if(sum > i) {
          console.log(i + "是盈数");
        }
        // 重置sum的值
        sum = 0;
      }
    }
  }
  // 调用函数
  abundantNum();
  
  
  /* 
  3.用户输入一个整数n：
    求1! + 2! + 3! + 4! + …… + n!的和
    叹号表示阶乘，如4! = 1 * 2 * 3 * 4 
  */
  function sum(n) {
    var multi = 1;
    if (n == 1) {
      // 当n为1时，开始回溯
      return 1;
    } else {
      for(var i = 1; i <= n; i++) {
        // 求n的阶乘
        multi *= i;
      }
      // 自调用函数
      return multi + sum(n-1);
    }
  }
  // 用户输入
  var user_input;
  // 判断是否有输入，直到用户输入值
  do {
    user_input = parseInt(prompt("请输入一个数字!"));
  }while (user_input == undefined)
  // 调用函数输出
  console.log(sum(user_input));
  
  
  /* 
  4. 求一个三位数，叫做“喇叭花数”，该三位数等与其每位数字的阶乘之和。
  */

  // 一开始选用递归方式求阶乘，会报错，超出堆栈调用大小，于是将递归换成for循环
  // function factorial(n){
  //   if(n == 1) {
  //     return 1;
  //   } else if (n == 0) {
  //     return 0;
  //   }
  //   return n * factorial(n-1)
  // } 
  function factorial(n) {
    var factorial = 1;
    // 求n的阶乘
    for(var i = 1; i <= n; i++) {
      factorial *= i;
    }
    return factorial;
  }
  function petunia() {
    // 三位数即从100~999的数
    for(var i = 100; i <= 999; i++) {
      // 将i装化为字符串，取个、十、百位数时可以用charAt()
      var i_str = i.toString();
      // 求个位数
      unitsDigit = parseInt(i_str.charAt(0));
      // 求十位数
      tenDigit = parseInt(i_str.charAt(1));
      // 求百位数
      hundredDigit = parseInt(i_str.charAt(2));
      var sum = factorial(unitsDigit) + factorial(tenDigit) + factorial(hundredDigit);
      if (sum == i) {
        console.log(i + "是喇叭花数");
      } else {
        // 重置sum
        sum = 0;
      }
    }
  }
  // 调用函数
  petunia();
  
  
  /* 
  5.如果整数A 的全部约数（包括1，不包括A 本身）之和等于B，且整数B 的全部约数
    （包括1，不包括B 本身）之和等于A，则称整数A和B是一对亲密数。
    求2000 以内的全部亲密数。
  */
  function closeNum() {
    var arr = [];
    var sum = 0;
    var approNum = [];
    var same;
    // 质数的约数只有1跟本身，先把质数去掉
    for (var i = 2; i <= 2000; i++) {
      if (i % 2 == 0) {
        // 添加进arr数组
        arr.push(i);
      }
    }
    console.log(arr);
    // 求出arr数组里面每一项的约数和
    for (var i = 0; i < arr.length; i++) {
      for (var j = 1; j < arr[i]; j++) {
        if (arr[i] % j == 0) {
          sum += j;
        }
      }
      // 添加进新的数组
      approNum.push(sum);
      sum = 0;
    }
    for(var i = 0; i < arr.length; i++) {
      for(var j = 0; j < approNum.length; j++) {
        // i不能等于j，否则会找到自己，i<j去掉重复的值
        if(arr[i] == approNum[j] && arr[j] == approNum[i] && i < j ) {
          console.log(arr[i] + "和" + arr[j] + "是亲密数");
        }
      }
  }
  // 调用函数
  closeNum();
  
  
  /* 
  6. 验证哥德巴赫猜想。一个偶数可以拆分成两个质数之和。
  */
  function verify(even) {
    var flag_i = 0;
    var flag_j = 0;
    // 偶数除以2，避免输出时重复值且减少遍历次数
    for(var i = 2; i < even / 2; i++) {
      var j = even - i;
      // 求拆分的两个数是否为质数
      for(var z = 1; z <= i; z++) {
        if(i % z == 0) {
          flag_i ++;
        }
      }
      for(var z = 1; z <= j; z++) {
        if(j % z == 0) {
          flag_j ++;
        }
      }
      // 两个都为质数，输出值
      if(flag_i == 2 && flag_j == 2) {
        console.log(even + "可以拆分成" + i + "和" + j + "之和");
      } else {
        // 将约数数量重置
        flag_i = 0;
        flag_j = 0;
      }
    }
  }
  // console.log("验证猜想");
  // 调用函数
  verify(50);
  
  
  /* 
  7.编写函数rev(char) 实现将字符串char倒置
    比如rev("spring") 返回"gnirps"
  */
  function rev(char) {
    // 将字符串转回或成数组，倒置后再转换为字符串
    return char.split("").reverse().join("");
  }
  console.log(rev("123456"));


  /* 
  8.将字符串"i come from beijing"倒置，即控制台输出"beijing from come i"
    语句直接写在程序中，不需要用户输入 
  */
  function rev2(char) {
    // 同第七题类似，由于字符串有空格，则用split(" ")
    return char.split(" ").reverse().join(" ");
  }
  console.log(rev2("i come from beijing"));


  /* 
  9. 编写函数rightchange(char,n) 实现字符串char循环右移n位。
  比如rightchange("abcdefg",2) 返回"fgabcde" 
  */
  function rightchange(char,n) {
    // 将字符串转换为数组
    arr_char = char.split("");
    for(var i = n; i > 0; i--) {
      // 依次拿出后n个，插入数组前面
      var el = arr_char.pop();
      arr_char.unshift(el);
    }
    // 转换成字符串
    return arr_char.join("");
  }
  console.log(rightchange("abcdefg",2));
  
  
  /*
    10. 编写函数maxr(char) 返回字符串char中最长的连续重复字母 
    比如maxr("mmmiijjjjkkkkkkssptr") 返回"kkkkkk"
  */
  function maxr(char) {
    var max_char;
    var count = 1;
    var max = 0;
    var start;
    var end;
    for(var i = 0; i < char.length; i++) {
      // 判断相邻两个字符是否一样，一样则加一
      if(char[i] == char[i + 1]) {
        count ++;
      } else {
        if (count > max) {
          // 求最大的重复次数
          max = count;
          // 将count值重置
          count = 1;
          // 求最大连续的字符
          max_char = char[i];
          // 求最大连续的字符最后一个数的下标
          max_index = i;
        }
      }
    }
    // 截取最长连续的字符输出
    console.log("max_arr:" + char.substring(max_index - max + 1, max_index + 1));
  }
  maxr("mmmiijjjjkkkkkkssptr");


  /*  
    11. 有10个学生的成绩存在数组中，请统计大于等于平均成绩的人数。
    成绩直接以数组形式写在程序中，不需要用户输入。
  */
  var arr = [100,50,80,88,95,78.5,55.5,64.5,87,45];
  function gtAvg(arr) {
    var sum = 0;
    var avg;
    var num = 0;
    // 求总数
    for(var i = 0; i < arr.length; i++) {
      sum += arr[i];
    }
    // 求平均数
    avg = sum / arr.length;
    // 判断统计大于平均数人数
    for (var i = 0; i < arr.length; i++) {
      if(arr[i] > avg) {
        num ++;
      }
    }
    return num;
  }
  console.log(gtAvg(arr));
 

  // 12. 将"i love javascript very much"的每个单词的第一个字母，变为大写。
  function firstUpperCase(char) {
    // 将字符串转换成数组
    var arr = char.split(" ");
    for(var i = 0; i < arr.length; i++) {
      // 去除第一个转换成大写，在连接上之后的字符串
      arr[i] = arr[i].substring(0,1).toUpperCase() + arr[i].substring(1);
    }
    // 将数组转换回字符串
    return arr.join(" ");
  }
  console.log(firstUpperCase("i love javascript very much"));

 
  // 13.求一组数中的最大值和最小值，以及所在位置的下标。
  function maxAndMin(arr) {
    var max, min;
    max = arr[0];
    min = arr[0];
    for(var i = 0; i < arr.length; i++) {
      // 遍历数组，找最大值
      if (max < arr[i+1]) {
        max = arr[i+1];
      }
      // 遍历数组，找最小值
      if (min > arr[i+1]) {
        min = arr[i+1];
      }
    }
    console.log("最大值为：" + max  +",最小值为：" + min);
  }
  maxAndMin([5,6,96,4,0,-7,5,6,3]);


  // 14.将数组用 | 或其他符号连接成一个字符串。
  function change(arr,char) {
    // 用join对数组进行连接并转换为字符串
    return arr.join(char);
  }
  console.log(change(['500','456','852','874'],"|"));


  // 15.将数组中值为 0 的项去掉，将不为 0 的值存入一个新的数组，生成新的数组。
  function newArr(arr) {
    var newArr = [];
    for(var i = 0; i < arr.length; i++) {
      // 遍历数组，如果值为0，则删除；否则放入新数组里
      if(arr[i] == 0) {
        arr.splice(i,1);
      } else {
        newArr.push(arr[i]);
      }
    }
    return newArr;
  }
  console.log(newArr([0,0,58,65,0,56,48,722,80]));


  /* 
  16.  数组去重；
    ```js
    [1,1,1,2,2,3,4,5,6,3,4,2,4,1,] ---> [1,2,3,4,5,6]
    ``` 
  */
  function noRepeat(arr) {
    // 定义个空数组
    var newArr = [];
    for (var i = 0; i < arr.length; i++) {
      // 新数组中没有相同的值，则放入新数组
      if (newArr.indexOf(arr[i]) === -1) {
        newArr.push(arr[i]);
      }
    }
    return newArr;
  }
  console.log(noRepeat([1, 1, 1, 2, 2, 3, 4, 5, 6, 3, 4, 2, 4, 1,]));


  /* 17.  数组排序；
    ```js
    [3,4,1,2,6,5] ---> [1,2,3,4,5,6]
    ``` 
  */
  function AscSort(arr) {
    // 用sort函数对数组进行排列
    arr = arr.sort(function(a, b){
      if(a > b) {
        return 1;
      } else if (a < b) {
        return -1;
      } else {
        return 0;
      }
    });
    return arr;
  }
  console.log(AscSort([3, 4, 1, 2, 6, 5]));



  /* 18.  数组转对象；
    ```js
    ['a','a','a','b','b','c','c','c','c','d','d','d','d']
    --->
    {
        a: 3,
        b: 2,
        c: 4,
        d: 4
    }
    ```
   */
   function toObject(arr) {
     var obj = {};
     for(var i = 0; i < arr.length; i++) {
      // 遍历数组，取值进行比较
       var letter = arr[i];
      //  判断如果对象中没有相同的key，则增加一个并赋值为1，有则在基础上加1
       if(!obj[letter]) {
         obj[letter] = 1;
       } else {
         obj[letter] ++;
       }
     }
    //  返回对象
     return obj;
   }
   console.log(toObject(['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd']));
   

  // 19.  使用js将99乘法表输出在控制台
  function multiTable(){
    var multi;
    var arr = [];
    for(var i = 1; i <= 9; i++) {
      for(var j = 1; j <= i; j++){
        multi = j * i;
        // 将结果存入字符串
        arr[j - 1] = j + "*" + i + "=" + multi
      }
      // 将数组装换成字符串
      console.log(arr.join(" "));
    }
  }
  multiTable();


  /*
  20. 买卖股票的最佳时机；给定一个数组，它的第i个元素是一支给定股票第i天的价格。如果你最多只允许完成一笔交易（即买入和卖出一支股票一次）设计一个算法来计算你所能获取的最大利润。
  注意：你不能再买入股票前卖出股票
  示例：
  ```
  输入：[7, 1, 5, 3, 6, 4]
  输出：5
  解释：在第2天（当天股票价格等于1）的时候买入，在第五天（当天股票价格等于6）的时候卖出，最大利润为 6 - 1 = 5。
  注意：利润不能使7 - 1 = 6，因为第二天的价格为1，第一天的价格为7，你是不可能在第二天买入股票然后等到第一天卖出的
  ```
  */ 
  function maxProfit(arr) {
    // 将数组倒置，方便计算
    arr = arr.reverse();
    temp = [];
    console.log(arr);
    for(var i = 0; i < arr.length - 1; i++) {
      for(var j = i + 1; j < arr.length - 1; j++) {
        // 用前一项减去后面其他项，即利润，将值放入新数组里
        temp.push(arr[i] - arr[j]);
      }
    }
    // 对所有可能产生的利润进行排序，输入最大利润
    temp.sort(function(a, b){
      if(a < b) {
        return 1;
      } else if (a > b) {
        return -1;
      } else if (a == b) {
        return 0;
      }
    });
    console.log(temp[0]);
  }
  maxProfit([7, 1, 5, 3, 6, 4]);
  </script>
</head>
<body>
  
</body>
</html>